import { VxeTableInstance } from "vxe-table";
import type { FormInstance } from "element-plus";
import { ElMessage } from "element-plus";
import { reactive, ref, nextTick } from "vue";
import localforage from "localforage";
import axios from "axios";
import JSZip from "jszip";
import async from "async";

export default function useList<T>({ url, FormInitData, ColumnNames }: any) {
  const API_URL = "/api";
  const listData = ref<T>();
  const page = ref(1);
  const limit = ref(5);
  const total = ref(0);
  const loading = ref(false);
  const dialogFormVisible = ref(false);
  const pageSize = ref(100); //每页数据量
  // const batchCount = ref(0); //总批次数
  const ruleFormRef = ref<FormInstance>();
  // 是否编辑
  const AddNus = ref(false);
  // 图片显示优化
  const uploadLoading = ref(false);
  // 是否显示弹框
  const showEdit = ref(false);

  const formData = reactive(FormInitData());
  // 详情页数据
  const tableData = ref([]);
  const getNewsList = async (currentPage: number, limit: number) => {
    loading.value = true;
    const res = await axios.get(
      `${API_URL}/${url}?_page=${currentPage}&_limit=${limit}`
    );
    total.value = +res.headers["x-total-count"];
    tableData.value = res.data;
    loading.value = false;
    await nextTick();
    setTimeout(async () => {
      // await storeAllImage();
      await getAllImage();
    }, 0);
  };
  // 提交表单
  const submitForm = async (formEl: FormInstance | undefined) => {
    if (!formEl) return;
    await formEl.validate(async (valid, fields) => {
      if (valid) {
        // 提交表单时可能是新增也可能是修改
        if (formData.id) {
          // 修改
          await axios.put(`${API_URL}/${url}/${formData.id}`, formData);
        } else {
          // 新增
          await axios.post(`${API_URL}/${url}`, formData);
        }
        ElMessage.success("保存成功");
        showEdit.value = false;
        getNewsList(1, limit.value);
        // 重新获取数据 修改则为当前页 新增则回到第一页
      } else {
        console.log("error submit!", fields);
      }
    });
  };
  // 清空表单
  const EmptyForm = () => {
    AddNus.value = false;
    Object.assign(formData, FormInitData());
  };
  // 删除操作
  const deleteNewsList = async (id: number) => {
    await axios.delete(`${API_URL}/${url}/${id}`);
    ElMessage.success("删除成功");
    getNewsList(page.value, limit.value);
  };
  // 新增操作
  const insertEvent = () => {
    showEdit.value = true;
    AddNus.value = true;
  };
  // 显示详情
  const Details = (row: T) => {
    showEdit.value = true;
    Object.assign(formData, row);
  };
  // 修改操作
  const recompose = (row: T) => {
    showEdit.value = true;
    AddNus.value = true;
    Object.assign(formData, row);
  };
  // 图片本地化操作
  const storage = localforage.createInstance({
    name: "image_storage",
    storeName: "images",
  });
  async function fetchImageAsBase64(url: string) {
    console.log(url);
    const response = await fetch(url);
    const blob = await response.blob(); // 现在已经存储在内存当中了，所以我们只需要从内存读取出来就可以了
    return new Promise((resolve, reject) => {
      const reader = new FileReader(); // 读取文件对象
      reader.onloadend = () => resolve(reader.result); // 读取完毕之后，会触发这个事件
      reader.onerror = reject; // 读取失败的时候，会触发这个事件
      reader.readAsDataURL(blob); // 读取文件对象
    });
  }
  // 存储单一图片
  async function storeImage(url: string) {
    const base64 = await fetchImageAsBase64(url);
    storage.setItem(url, base64);
  }
  // 取图片
  async function getImage(key: string) {
    const image = await storage.getItem(key);
    return image;
  }
  // 存储所有图片
  async function storeAllImage() {
    const images = document.querySelectorAll(".image");
    for (let i = 0; i < images.length; i++) {
      const url = images[i].getAttribute("data-src")!;
      const key = url;
      // 先进行查询，如果本地已经有了，就不再存储，没有才存储
      const imageInStorage = await getImage(key);
      if (!imageInStorage) {
        await storeImage(url);
      }
    }
  }

  // 取出所有图片
  async function getAllImage() {
    const images = document.querySelectorAll(".image");
    for (const image of images) {
      const key = image.getAttribute("data-src")!;
      const imageInStorage = await getImage(key);
      if (imageInStorage) {
        (image as any).src = imageInStorage;
      }
    }
  }

  //将数据导出为CSV文件
  const exportCsv = async (batchIndex: number) => {
    //定义CSV列头
    const columnNames = ColumnNames;
    // 从服务器获取数据
    const res = await axios.get(
      `http://localhost:3000/${url}?_page=${batchIndex + 1}&_limit=${pageSize.value}`
    );
    const batchData = res.data;
    //将列头和数据拼接为CSV字符串
    let csvContent = columnNames.join(",") + "\n";
    //对批次数据进行遍历，将每一行数据拼接为CSV字符串
    batchData.forEach(function (item: any) {
      const row: any[] = []
      columnNames.forEach(function (name: any) {
        row.push(item[name]);
      });
      csvContent += row.join(",") + "\n";
    });
    return {
      fileName: `data-${batchIndex + 1}.csv`,
      content: csvContent,
    };
  };

  // 导出为zip压缩文件
  const exportZip = async () => {
    loading.value = true;
    // 计算总批次
    const batchCount = Math.ceil(total.value / pageSize.value); //总批次数
    // 创建一个jszip的实例
    const zip = new JSZip();

    // 包含n个导出cvs文件到zip包的任务函数的数组
    const tasks = []
    for (let index = 0; index < batchCount; index++) {
      tasks.push(
        async () => {
          const { fileName, content } = await exportCsv(index);
          // 将CSV文件放入压缩包中
          zip.file(fileName, content);
          // 设置当前的导出批次
          page.value = index + 1;
        }
      )
    }
    // 同时进行五个并行任务
    await async.parallelLimit(tasks, 10);
    // 生成压缩包
    const blob = await zip.generateAsync({ type: "blob" });
    // 创建一个url
    const url = URL.createObjectURL(blob);
    // 创建a标签
    const link = document.createElement("a");
    // 设置a标签的链接
    link.href = url;
    // 设置下载的文件名
    link.download = "data.zip";
    // 模拟点击a标签下载文件
    link.click();
    // 释放URL对象
    URL.revokeObjectURL(url);
    loading.value = false;
  };

  // 导出其他文件格式（单页数据）
  const xTable = ref<VxeTableInstance>();
  return {
    listData,
    page,
    limit,
    total,
    loading,
    dialogFormVisible,
    ruleFormRef,
    formData,
    AddNus,
    tableData,
    submitForm,
    EmptyForm,
    insertEvent,
    recompose,
    deleteNewsList,
    Details,
    getNewsList,
    uploadLoading,
    showEdit,
    storeAllImage,
    getAllImage,
    exportZip,
    xTable,
  };
}
